#pragma once
#include "sock.hpp"

#include <sys/epoll.h>
#define BACKLOG 5
#define SIZE 256
#define TIMEOUT -1
#define MAXNUM 64

namespace ns_epoll{
	class EpollServer{
	private:
		int port;
		int epfd;
		int listen_sock;
	public:
		EpollServer(int _port):port(_port){}
		
	public:
		void InitEpollServer() {
			listen_sock = ns_sock::Sock::Socket();
			ns_sock::Sock::Bind(listen_sock, port);
			ns_sock::Sock::Listen(listen_sock, BACKLOG);
			//创建epoll模型
			if ((epfd = epoll_create(SIZE)) < 0) {
				std::cerr << "epoll_creat error!!" << std::endl;
				exit(4);
			}
            std::cout<<"server start"<<std::endl;
		}

		void Run() {
			AddEvent(listen_sock, EPOLLIN);
			struct epoll_event revs[MAXNUM];
			while (true) {
				//返回值num表示就绪的事件数，内核会将就绪事件依次放入revs中
				int num = epoll_wait(epfd, revs, MAXNUM, TIMEOUT);
				if (num > 0) {
					for (int i = 0; i < num; ++i) {
						if (revs[i].events & EPOLLIN) {
							//读事件就绪
							if (revs[i].data.fd == listen_sock) {
								//连接事件就绪

								struct sockaddr_in peer;
								socklen_t len = sizeof(peer);

								int sock = accept(listen_sock, (struct sockaddr*)&peer, &len);
								if (sock < 0) {
									std::cerr << "accept error!!!" << std::endl;
									continue;
								}
								//获取到一个新连接
								//打印客户端信息
								uint16_t peer_port = htons(peer.sin_port);
								std::string peer_ip = inet_ntoa(peer.sin_addr);

								std::cout << "有一个新连接 " << "ip :[" << peer_ip << "]  port: [" << peer_port << "]" << std::endl;
								//添加对sock的读事件检测
								if (!AddEvent(sock, EPOLLIN)) {
									std::cerr << "Add error!!!" << std::endl;
									close(sock);
								}
							}
							else {
								//其他读事件就绪()
								char buffer[1024];
								ssize_t size = recv(revs[i].data.fd, buffer, sizeof(buffer)-1, 0);
								//bug
								if (size > 0) {
									buffer[size] = 0;
									std::cout << "echo#" << buffer ;
								}
								else if(size == 0) {
									std::cout << "client close!!" << std::endl;
                                    if(!DelEvent(revs[i].data.fd)){
                                        std::cerr<<"delevent error"<<std::endl;
                                    }
									close(revs[i].data.fd);
								}
							}
						}
						else if (revs[i].events == EPOLLOUT) {
							//写事件就绪
						}
						else {
							//其他事件就绪
						}
					}
				}
				else if (num == 0) {
					//timeout
					std::cout << "timeout!!!" << std::endl;
				}
				else {
					//err
					std::cerr << "epoll error!!!" << std::endl;
				}
			}
		}

		bool AddEvent(int sock, int event) {
			struct epoll_event ev;
			ev.events = 0;
			ev.events |= event;
            ev.data.fd = sock;
			if (epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
				std::cerr << "epoll_ctr error  fd:" <<sock << std::endl;
				return false;
			}
			return true;
		}
		bool DelEvent(int sock) {
			if (epoll_ctl(epfd, EPOLL_CTL_DEL, sock, nullptr) < 0) {
				std::cerr << "epoll_ctl error  fd:" << sock << std::endl;
				return false;
			}
			return true;
		}

		~EpollServer() {
			if (listen_sock >= 0) close(listen_sock);
			if (epfd >= 0) close(epfd);
		}
	};
}  
